#include "file_manager.h"

// 使用fcntl对已打开的文件描述符加锁
int lock_file(int fd, LockType type) {
    struct flock fl;
    memset(&fl, 0, sizeof(fl));
    
    fl.l_type = (type == LOCK_READ) ? F_RDLCK : F_WRLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 0;  // 0表示锁定整个文件
    
    if (fcntl(fd, F_SETLK, &fl) == -1) {
        if (errno == EACCES || errno == EAGAIN) {
            printf("文件已被锁定\n");
        } else {
            printf("加锁失败: %s\n", strerror(errno));
        }
        return -1;
    }
    
    printf("文件加锁成功\n");
    return 0;
}

// 释放文件锁
int unlock_file(int fd) {
    struct flock fl;
    memset(&fl, 0, sizeof(fl));
    
    fl.l_type = F_UNLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 0;
    
    if (fcntl(fd, F_SETLK, &fl) == -1) {
        printf("解锁失败: %s\n", strerror(errno));
        return -1;
    }
    
    printf("文件解锁成功\n");
    return 0;
}

// 检查文件是否被锁定
int file_is_locked(const char *path) {
    int fd = open(path, O_RDONLY);
    if (fd == -1) {
        return 0;  // 文件不存在或无法打开，视为未锁定
    }
    
    struct flock fl;
    memset(&fl, 0, sizeof(fl));
    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 0;
    
    int result = fcntl(fd, F_GETLK, &fl);
    close(fd);
    
    if (result == 0 && fl.l_type != F_UNLCK) {
        return 1;  // 文件已被锁定
    }
    
    return 0;  // 文件未被锁定
}

// 根据文件路径加锁
int lock_file_by_path(const char *path, LockType type) {
    int flags = (type == LOCK_READ) ? O_RDONLY : O_WRONLY;
    int fd = open(path, flags);
    if (fd == -1) {
        printf("无法打开文件: %s\n", strerror(errno));
        return -1;
    }
    
    int result = lock_file(fd, type);
    close(fd);  // 关闭文件描述符，文件锁会被自动释放
    
    return result;
}

// 根据文件路径解锁
int unlock_file_by_path(const char *path) {
    // 检查是否是我们通过write命令保持锁定的文件
    for (int i = 0; i < num_locked_files; i++) {
        if (strcmp(locked_files[i].path, path) == 0) {
            // 解锁并关闭文件
            unlock_file(locked_files[i].fd);
            fclose(locked_files[i].file);
            
            // 从数组中移除（移动后面的元素）
            for (int j = i; j < num_locked_files - 1; j++) {
                locked_files[j] = locked_files[j + 1];
            }
            num_locked_files--;
            
            printf("成功解锁并关闭文件: %s\n", path);
            return 0;
        }
    }
    
    // 如果不是我们保持锁定的文件
    printf("警告: 无法直接通过路径解锁其他进程持有的锁\n");
    printf("文件锁通常会随着持有锁的进程终止或文件描述符关闭而自动释放\n");
    return 0;
}

// 清理所有保持锁定的文件
void cleanup_locked_files() {
    for (int i = 0; i < num_locked_files; i++) {
        printf("自动清理锁定文件: %s\n", locked_files[i].path);
        unlock_file(locked_files[i].fd);
        fclose(locked_files[i].file);
    }
    num_locked_files = 0;
}